package com.zzg.mybatis.generator.plugins;

import org.mybatis.generator.api.*;
import org.mybatis.generator.api.dom.xml.*;

import com.zzg.mybatis.generator.util.StringUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

/**
 * mapperXml文件参数名自定义
 */
public class CustomizeDAOXmlPlugin extends PluginAdapter{

	/**
	 * 获取别名
	 * @param introspectedTable
	 * @return
	 */
	private String getAlias(IntrospectedTable introspectedTable){
		//获取新的id属性值
		FullyQualifiedTable fullyTableName = introspectedTable.getFullyQualifiedTable();
		String domainObjectName = fullyTableName.getDomainObjectName();
		int secondIndex = domainObjectName.indexOf("_",domainObjectName.indexOf("_")+1);
		String tempStr = StringUtil.customClassName(domainObjectName.substring(secondIndex+1).replace("Po",""),"");
		return tempStr;
	}
	
	/**
	 * 重置属性
	 * @param element
	 * @param introspectedTable
	 * @param retainList 需要保留的属性
	 * @param map 需要替换的属性集合
	 */
	private void resetContent(XmlElement element,IntrospectedTable introspectedTable,List<String> retainList,Map<String,String> map){
		String elName = element.getName();
		List<Element> eleList = element.getElements();
		List<Attribute> attrList = element.getAttributes();
		String schema = introspectedTable.getFullyQualifiedTable().getIntrospectedSchema();
		//自定义属性
		for(Iterator<Attribute> it = attrList.iterator();it.hasNext();){
			Attribute attr = (Attribute)it.next();
			if(attrList.contains(attr)){
				if(!retainList.contains(attr.getName())){
					it.remove();
				}
			}
		}
		for(Entry<String,String> entry:map.entrySet()){
			attrList.add(new Attribute(entry.getKey(),entry.getValue()));
	    }
		//自定义sql
		if("select".equals(elName)){
			for(int i=0;i<eleList.size();i++){
				Element el = eleList.get(i);
				if(i==1){
					XmlElement xel = (XmlElement) el;
					List<String> colList = introspectedTable.getBaseColumns()
												.stream().map(e -> {return "a."+e.getActualColumnName()+" as "+e.getActualColumnName();}).collect(Collectors.toList());
					StringBuilder sb = new StringBuilder();
					int rowNum = (int)Math.ceil(colList.size()/5);
					for(int j=0;j<rowNum;j++){
						for(int k=5*j;k<5*(j+1);k++){
							if(j==rowNum-1 && k==5*(j+1)-1){
								sb.append(colList.get(k));
							}else{
								sb.append(colList.get(k)+",");
							}
						}
						if(j==0){
							Collections.replaceAll(eleList,xel,new TextElement("	"+sb.toString()));
							sb = new StringBuilder();
						}else{
							eleList.add(2,new TextElement("	"+sb.toString()));
							sb = new StringBuilder();
						}
					}
				}
				if(i==3){
					TextElement tel = (TextElement) el;
					Collections.replaceAll(eleList,el,new TextElement(tel.getContent().replace(schema+".","")+" a"));
				}
			}
			XmlElement xel = new XmlElement("choose");
			XmlElement whenEl = new XmlElement("when");
			Attribute whenAttr = new Attribute("test","sort != null and sort != ''");
			whenEl.addElement(new TextElement(" order by ${sort} "));
			XmlElement whenIfEl = new XmlElement("if");
			whenIfEl.addAttribute(new Attribute("test","order != null and order != ''"));
			whenIfEl.addElement(new TextElement(" ${order}"));
			whenEl.addElement(whenIfEl);
			xel.addElement(whenEl);
			xel.addAttribute(whenAttr);
			XmlElement otherEl = new XmlElement("otherwise");
			otherEl.addElement(new TextElement("order by ID"));
			xel.addElement(otherEl);
			eleList.add(xel);
		}else{
			for(int i=0;i<eleList.size();i++){
				Element el = eleList.get(i);
				if("insert".equals(elName)){
					if(i==0){
						XmlElement xel = (XmlElement) el;
						List<Attribute> selectKeyList = xel.getAttributes();
						for(Attribute attr:selectKeyList){
							if("order".equals(attr.getName())){
								Collections.replaceAll(selectKeyList,attr,new Attribute("order","BEFORE"));
								break;
							}
						}
					}
					if(i==1){
						TextElement tel = (TextElement) el;
						Collections.replaceAll(eleList,el,new TextElement(tel.getContent().replace(schema+".","")));
					}
					if(i==2){
						XmlElement xel = (XmlElement) el;
						xel.addElement(0,new TextElement("ID,"));
					}
					if(i==3){
						XmlElement xel = (XmlElement) el;
						xel.addElement(0,new TextElement("#{id,jdbcType=DECIMAL},"));
					}
				}else{
					if(i==0){
						TextElement tel = (TextElement) el;
						Collections.replaceAll(eleList,el,new TextElement(tel.getContent().replace(schema+".","")));
					}
				}
			}
		}
	}

	@Override
	public boolean validate(List<String> warnings){
		return true;
	}

	@Override
	public boolean sqlMapSelectAllElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapBaseColumnListElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapBlobColumnListElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapResultMapWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapCountByExampleElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapDeleteByExampleElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapDeleteByPrimaryKeyElementGenerated(XmlElement element,IntrospectedTable introspectedTable){
		List<String> remainList = new ArrayList<String>();
		Map<String,String> map = new HashMap<String,String>();
		map.put("id",element.getName()+getAlias(introspectedTable));
		map.put("parameterType",introspectedTable.getBaseRecordType());
		resetContent(element,introspectedTable,remainList,map);
		return true;
	}

	@Override
	public boolean sqlMapDocumentGenerated(Document document,IntrospectedTable introspectedTable){
		String tableRemarks = introspectedTable.getRemarks();
		List<Element> eleList = document.getRootElement().getElements();
		for(int i=0;i<4;i++){
			document.getRootElement().addElement(i*2,new TextElement("<!-- {remark} -->"));
		}
		for(int i=0;i<eleList.size();i++){
			if(i%2==0){
				TextElement tel = (TextElement)eleList.get(i);
				XmlElement xel = (XmlElement)eleList.get(i+1);
				String remark = "";
				if("select".equals(xel.getName())){
					remark = "查询";
				}else if("delete".equals(xel.getName())){
					remark = "删除";
				}else if("insert".equals(xel.getName())){
					remark = "新增";
				}else if("update".equals(xel.getName())){
					remark = "更新";
				}
				Collections.replaceAll(eleList,tel,new TextElement(tel.getContent().replace("{remark}",remark + tableRemarks)));
			}
		}
		return true;
	}

	@Override
	public boolean sqlMapExampleWhereClauseElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapGenerated(GeneratedXmlFile sqlMap,IntrospectedTable introspectedTable){
		return true;
	}

	@Override
	public boolean sqlMapInsertElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapResultMapWithBLOBsElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapSelectByPrimaryKeyElementGenerated(XmlElement element,IntrospectedTable introspectedTable){
		List<String> remainList = new ArrayList<String>();
		remainList.add("");
		Map<String,String> map = new HashMap<String,String>();
		map.put("id",element.getName()+getAlias(introspectedTable));
		map.put("resultType",introspectedTable.getBaseRecordType());
		resetContent(element,introspectedTable,remainList,map);
		return true;
	}

	@Override
	public boolean sqlMapUpdateByExampleSelectiveElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapUpdateByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapUpdateByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapUpdateByPrimaryKeySelectiveElementGenerated(XmlElement element,IntrospectedTable introspectedTable){
		List<String> remainList = new ArrayList<String>();
		remainList.add("parameterType");
		Map<String,String> map = new HashMap<String,String>();
		map.put("id",element.getName()+getAlias(introspectedTable));
		resetContent(element,introspectedTable,remainList,map);
		return true;
	}

	@Override
	public boolean sqlMapUpdateByPrimaryKeyWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapUpdateByPrimaryKeyWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
		return false;
	}

	@Override
	public boolean sqlMapInsertSelectiveElementGenerated(XmlElement element,IntrospectedTable introspectedTable){
		List<String> remainList = new ArrayList<String>();
		remainList.add("parameterType");
		Map<String,String> map = new HashMap<String,String>();
		map.put("id",element.getName()+getAlias(introspectedTable));
		resetContent(element,introspectedTable,remainList,map);
		return true;
	}
}